/*
 * MiscellaneousOptionsPanel.java
 *
 * Created on December 6, 2007, 8:14 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */
package filecopier.gui.tabs;

import java.awt.event.ActionEvent;
import javax.swing.JPanel;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JRadioButton;
import javax.swing.BorderFactory;
import javax.swing.JComboBox;
import javax.swing.UIManager;
import javax.swing.JFormattedTextField;
import javax.swing.JTextField;
import javax.swing.JLabel;
import javax.swing.JCheckBox;
import javax.swing.text.NumberFormatter;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.text.NumberFormat;
import java.beans.PropertyChangeEvent;
import filecopier.Singleton;
import filecopier.ActionCommand;
import filecopier.options.Options;
import filecopier.gui.Utilities;
import filecopier.gui.restore.RestoreScriptPathWrapper;
import filecopier.script.ScriptPath;
import custom.util.MRUException;

import org.apache.log4j.Level;

/**
 *
 * @author david
 */
public class MiscellaneousOptionsPanel extends JPanel implements ActionCommand {

    private Box lookAndFeelBox = null;
    private Box miscellaneousOptionsBox = null;
    private Box copyPathBox = null;
    private Box restorePathBox = null;
    private Options options = null;

    /** Creates a new instance of MiscellaneousOptionsPanel */
    public MiscellaneousOptionsPanel() {
        super();
        initialize();
    }

    private void initialize() {
        options = Singleton.getInstance().getOptions();
        this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        this.add(getMiscellaneousOptionsBox());
        this.add(getLookAndFeelBox());
        this.add(getCopyPathBox());
        this.add(getRestorePathBox());
    }

    private Box getCopyPathBox() {
        if (copyPathBox == null) {
            copyPathBox = new PathBox(Options.ActionMode.Copy);
        }
        return copyPathBox;
    }

    private Box getRestorePathBox() {
        if (restorePathBox == null) {
            restorePathBox = new PathBox(Options.ActionMode.Restore);
        }
        return restorePathBox;
    }

    private Box getMiscellaneousOptionsBox() {
        if (miscellaneousOptionsBox == null) {
            miscellaneousOptionsBox = new MiscellaneousOptionsBox();
            miscellaneousOptionsBox.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
        }
        return miscellaneousOptionsBox;
    }

    private Box getLookAndFeelBox() {
        if (lookAndFeelBox == null) {
            lookAndFeelBox = new LookAndFeelBox();
            lookAndFeelBox.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
        }
        return lookAndFeelBox;
    }

    public void doAction() {
        ((MiscellaneousOptionsBox) miscellaneousOptionsBox).setDefaults();
        ((LookAndFeelBox) lookAndFeelBox).setDefaults();
        ((PathBox) copyPathBox).setDefaults();
        ((PathBox) restorePathBox).setDefaults();
    }

    class MiscellaneousOptionsBox extends Box {

        private Box logOptionsBox = null;
        private Box mostRecentlyUsedMaxBox = null;
        private Box miscellaneousBox = null;

        public MiscellaneousOptionsBox() {
            super(BoxLayout.X_AXIS);
            this.add(getLogOptionsBox());
            this.add(Box.createRigidArea(new java.awt.Dimension(60, 0)));
            this.add(getMiscellaneousBox());
        }

        private Box getLogOptionsBox() {
            if (logOptionsBox == null) {
                logOptionsBox = new LogOptionsBox();
            }
            return logOptionsBox;
        }

        private Box getMostRecentlyUsedMaxBox() {
            if (mostRecentlyUsedMaxBox == null) {
                mostRecentlyUsedMaxBox = new MostRecentlyUsedMaxBox();
            }
            return mostRecentlyUsedMaxBox;
        }

        private Box getMiscellaneousBox() {
            if (miscellaneousBox == null) {
                miscellaneousBox = new Box(BoxLayout.Y_AXIS);
                miscellaneousBox.add(getMostRecentlyUsedMaxBox());
            }
            return miscellaneousBox;
        }

        public void setDefaults() {
            ((LogOptionsBox) logOptionsBox).setDefaults();
            ((MostRecentlyUsedMaxBox) mostRecentlyUsedMaxBox).setDefaults();
        }

        class LogOptionsBox extends Box { //class LogOptionsBox extends javax.swing.JPanel

            private ButtonGroup buttonGrp = null;
            private JRadioButton debugBtn = null;
            private JRadioButton infoBtn = null;
            private JRadioButton warnBtn = null;
            private JRadioButton errorBtn = null;

            public LogOptionsBox() {
                super(BoxLayout.Y_AXIS);
                initialize();
            }

            private void initialize() {
                // Add border around the panel
                this.setBorder(BorderFactory.createCompoundBorder(
                        BorderFactory.createTitledBorder("Log Level"),
                        BorderFactory.createEmptyBorder(5, 5, 5, 5)));			// Add the radio buttons to the panel and the button group	
                this.add(getDebugBtn());
                this.add(getInfoBtn());
                this.add(getWarnBtn());
                this.add(getErrorBtn());
                this.getButtonGrp();
            }

            private ButtonGroup getButtonGrp() {
                if (buttonGrp == null) {
                    buttonGrp = new ButtonGroup();
                    buttonGrp.add(debugBtn);
                    buttonGrp.add(infoBtn);
                    buttonGrp.add(warnBtn);
                    buttonGrp.add(errorBtn);
                }
                return buttonGrp;
            }

            /**
             * This method initializes warningsBtn   
             *   
             * 
             * @return javax.swing.JRadioButton
             */
            private JRadioButton getWarnBtn() {
                if (warnBtn == null) {
                    warnBtn = new JRadioButton("Warn");
                    warnBtn.setMnemonic(java.awt.event.KeyEvent.VK_W);
                    warnBtn.setToolTipText("Log warnings and error messages only.");
                    warnBtn.setSelected(options.getLogLevel().equals(Level.WARN));
                    warnBtn.addActionListener(new java.awt.event.ActionListener() {

                        public void actionPerformed(java.awt.event.ActionEvent e) {
                            options.setLogLevel(Level.WARN);
                            Singleton s = Singleton.getInstance();
                            s.setLoggerLevels();
                            s.getFileAlwaysLogger().info("Log level changed to " + Level.WARN);
                        }
                    });
                }
                return warnBtn;
            }

            /**
             * This method initializes normalBtn 
             *   
             * @return javax.swing.JRadioButton  
             */
            private JRadioButton getInfoBtn() {
                if (infoBtn == null) {
                    infoBtn = new JRadioButton("Info");
                    infoBtn.setMnemonic(java.awt.event.KeyEvent.VK_I);
                    infoBtn.setToolTipText("Log most messages.");
                    infoBtn.setSelected(options.getLogLevel().equals(Level.INFO));

                    infoBtn.addActionListener(new java.awt.event.ActionListener() {

                        public void actionPerformed(java.awt.event.ActionEvent e) {
                            options.setLogLevel(Level.INFO);
                            Singleton s = Singleton.getInstance();
                            s.setLoggerLevels();
                            s.getFileAlwaysLogger().info("Log level changed to " + Level.INFO);
                        }
                    });
                }
                return infoBtn;
            }

            /**
             * This method initializes allBtn    
             *   
             * 
             * @return javax.swing.JRadioButton
             */
            private JRadioButton getDebugBtn() {
                if (debugBtn == null) {
                    debugBtn = new JRadioButton("Debug");
                    debugBtn.setMnemonic(java.awt.event.KeyEvent.VK_B);
                    debugBtn.setToolTipText("Log debug messages.");
                    debugBtn.setSelected(options.getLogLevel().equals(Level.DEBUG));

                    debugBtn.addActionListener(new java.awt.event.ActionListener() {

                        public void actionPerformed(java.awt.event.ActionEvent e) {
                            options.setLogLevel(Level.DEBUG);
                            Singleton s = Singleton.getInstance();
                            s.setLoggerLevels();
                            s.getFileAlwaysLogger().info("Log level changed to " + Level.DEBUG);
                        }
                    });
                }
                return debugBtn;
            }

            private JRadioButton getErrorBtn() {
                if (errorBtn == null) {
                    errorBtn = new JRadioButton("Error");
                    errorBtn.setMnemonic(java.awt.event.KeyEvent.VK_R);
                    errorBtn.setToolTipText("Log error messages.");
                    errorBtn.setSelected(options.getLogLevel().equals(Level.ERROR));

                    errorBtn.addActionListener(new java.awt.event.ActionListener() {

                        public void actionPerformed(java.awt.event.ActionEvent e) {
                            options.setLogLevel(Level.ERROR);
                            Singleton s = Singleton.getInstance();
                            s.setLoggerLevels();
                            s.getFileAlwaysLogger().info("Log level changed to " + Level.ERROR);
                        }
                    });
                }
                return errorBtn;
            }

            public void setDefaults() {
                infoBtn.doClick();
            }

            /*
            private void testLogger(org.apache.log4j.Logger logger) {
                logger.debug("This is a debug message");
                logger.info("This is an info message");
                logger.warn("This is a warn message");
                logger.error("This is an error message");
            }
             */ 
        }

        class MostRecentlyUsedMaxBox extends Box {

            private JFormattedTextField mostRecentlyUsedMaxField = null;
            private JLabel prefix = null;
            private JLabel suffix = null;
            private int newMax = 0;

            public MostRecentlyUsedMaxBox() {
                super(BoxLayout.X_AXIS);
                initialize();
            }

            private void initialize() {
                this.add(getPrefix());
                this.add(getMostRecentlyUsedMaxField());
                this.add(getSuffix());
                this.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
            }

            private JLabel getPrefix() {
                if (prefix == null) {
                    prefix = new JLabel("Retain ");
                }
                return prefix;
            }

            private JLabel getSuffix() {
                if (suffix == null) {
                    suffix = new JLabel(" items in most recently used lists.");
                }
                return suffix;
            }

            private JFormattedTextField getMostRecentlyUsedMaxField() {
                if (mostRecentlyUsedMaxField == null) {
                    // Set up number format and give it a max of two digits.
                    NumberFormat displayFormat = NumberFormat.getIntegerInstance();
                    displayFormat.setMinimumIntegerDigits(1);
                    displayFormat.setMaximumIntegerDigits(2);

                    // Set up number formatter with number format with an accepted range of 1 to 12.
                    NumberFormatter displayFormatter = new NumberFormatter(displayFormat);
                    displayFormatter.setValueClass(Integer.class);
                    displayFormatter.setMinimum(1);
                    displayFormatter.setMaximum(12);

                    mostRecentlyUsedMaxField = new JFormattedTextField(displayFormatter);
                    mostRecentlyUsedMaxField.setColumns(2);
                    mostRecentlyUsedMaxField.setToolTipText("<html>Maximum number of most recently used script file names to be saved for<p>" +
                            "retention in the To and From script lists. The maximum number can be<p>" +
                            "between 1 and 12.</html>");
                    mostRecentlyUsedMaxField.setFocusLostBehavior(JFormattedTextField.COMMIT_OR_REVERT);

                    mostRecentlyUsedMaxField.setComponentPopupMenu(Utilities.createEditPopupMenu(mostRecentlyUsedMaxField));
                    mostRecentlyUsedMaxField.setMaximumSize(new java.awt.Dimension(24, mostRecentlyUsedMaxField.getPreferredSize().height));
                    mostRecentlyUsedMaxField.setValue(new Integer(options.getMostRecentlyUsed()[Options.FROM_IDX].getMaxSize()));

                    mostRecentlyUsedMaxField.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

                        public void propertyChange(PropertyChangeEvent evt) {
                            newMax = ((Integer) mostRecentlyUsedMaxField.getValue()).intValue();
                            if (newMax != options.getMostRecentlyUsed()[Options.FROM_IDX].getMaxSize()) {
                                try {
                                    options.getMostRecentlyUsed()[Options.FROM_IDX].setMaxSize(newMax);
                                    options.getMostRecentlyUsed()[Options.TO_IDX].setMaxSize(newMax);
                                } catch (MRUException e) {
                                    // figure out what to do with this. Probably, log it as a warning.
                                }
                            }
                        }
                    });
                }

                return mostRecentlyUsedMaxField;
            }

            public void setDefaults() {
                if ((Integer) mostRecentlyUsedMaxField.getValue() != Options.defaultMostRecentlyUsed) {
                    mostRecentlyUsedMaxField.setValue(Options.defaultMostRecentlyUsed);
                }
            }
        }
    }

    class LookAndFeelBox extends Box {

        private JComboBox lookAndFeelComboBox = null;
        private JCheckBox useWindowDecorationsChk = null;
        private JLabel lookAndFeelMsgLbl = null;
        /** Array of installed look and feels */
        private UIManager.LookAndFeelInfo[] installedLookAndFeels = null;

        public LookAndFeelBox() {
            super(BoxLayout.Y_AXIS);
            initialize();
        }

        private void initialize() {
            setBorder(BorderFactory.createCompoundBorder(
                    BorderFactory.createTitledBorder("Look & Feel"),
                    BorderFactory.createEmptyBorder(5, 5, 5, 5)));			// Add the radio buttons to the panel and the button group
            add(getLookAndFeelMsgLbl());
            add(getLookAndFeelComboBox());
            add(getUseWindowDecorationsChkBox());
        }

        private UIManager.LookAndFeelInfo[] getInstalledLookAndFeels() {
            if (installedLookAndFeels == null) {
                installedLookAndFeels = UIManager.getInstalledLookAndFeels();
            }
            return installedLookAndFeels;
        }

        private JComboBox getLookAndFeelComboBox() {
            if (lookAndFeelComboBox == null) {
                getInstalledLookAndFeels();
                String[] lookAndFeels = new String[installedLookAndFeels.length];
                for (int i = 0; i < installedLookAndFeels.length; ++i) {
                    lookAndFeels[i] = installedLookAndFeels[i].getName();
                }
                lookAndFeelComboBox = new JComboBox(lookAndFeels);
                lookAndFeelComboBox.setMaximumSize(new java.awt.Dimension(Short.MAX_VALUE, lookAndFeelComboBox.getPreferredSize().height));
                lookAndFeelComboBox.setToolTipText("Choose from a list of installed look and feels");
                lookAndFeelComboBox.setSelectedItem(options.getLookAndFeel().getName());

                lookAndFeelComboBox.addItemListener(new java.awt.event.ItemListener() {

                    public void itemStateChanged(java.awt.event.ItemEvent e) {
                        if(e.getStateChange() == java.awt.event.ItemEvent.SELECTED) {
                            int idx = lookAndFeelComboBox.getSelectedIndex();
                            if (idx >= 0) {
                                options.setLookAndFeel(installedLookAndFeels[idx]);
                            }
                        }
                    }
                });
            }

            return lookAndFeelComboBox;
        }
        
        private JCheckBox getUseWindowDecorationsChkBox() {
            if(useWindowDecorationsChk == null) {
                useWindowDecorationsChk = new JCheckBox("Draw window borders using Swing look & feel");
                useWindowDecorationsChk.setMnemonic(java.awt.event.KeyEvent.VK_N);
                useWindowDecorationsChk.setToolTipText("<html>"
                    + "Attempt to use swing's look & feel to draw window borders. If the look & feel in use<p>"
                    + "does not provide its own window decorations, native window decorations will be used.</hml>");
                useWindowDecorationsChk.setSelected(options.useWindowDecorations());
                
                useWindowDecorationsChk.addActionListener(new java.awt.event.ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                        boolean request = useWindowDecorationsChk.isSelected();
                        options.setWindowDecorations(request);
                    }
                });
            }
            return useWindowDecorationsChk;
        }
        
        private JLabel getLookAndFeelMsgLbl() {
            if(lookAndFeelMsgLbl == null) {
                lookAndFeelMsgLbl = new JLabel("Restart FileCopier for look & feel changes to take effect.");
            }
            return lookAndFeelMsgLbl;
        }

        public void setDefaults() {
            if (!lookAndFeelComboBox.getSelectedItem().equals(Options.defaultLookAndFeel.getName())) {
                lookAndFeelComboBox.setSelectedItem(Options.defaultLookAndFeel.getName());
            }
            useWindowDecorationsChk.setSelected(Options.defaultUseWindowDecorations);
        }
    }

    class PathBox extends Box implements DocumentListener {

        private JTextField pathDisplay = null;
        private ScriptPath scriptPath = null;
        private RestoreScriptPathWrapper restoreScriptPathWrapper = null;
        private Options.ActionMode actionMode = null;

        public PathBox(Options.ActionMode actionMode) {
            super(BoxLayout.PAGE_AXIS);
            this.initialize(actionMode);
        }

        private void initialize(Options.ActionMode actionMode) {
            this.actionMode = actionMode;
            if(actionMode == Options.ActionMode.Copy) {
                getScriptPath();
            } else {
                getRestoreScriptPathWrapper();
            }
            this.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
            this.setBorder(BorderFactory.createCompoundBorder(
                    BorderFactory.createTitledBorder(actionMode == Options.ActionMode.Copy ? "Copy Path" : "Restore Path"),
                    BorderFactory.createEmptyBorder(5, 5, 5, 5)));

            this.add(getPathDisplay());
        }
        
        private ScriptPath getScriptPath() {
            if (scriptPath == null) {
                scriptPath = options.getCopyPath();
            }
            return scriptPath;
        }
        
        private RestoreScriptPathWrapper getRestoreScriptPathWrapper() {
            if(restoreScriptPathWrapper == null) {
                restoreScriptPathWrapper = options.getRestorePathWrapper();
                scriptPath = restoreScriptPathWrapper.getRestorePath();
            }
            return restoreScriptPathWrapper;
        }

        private JTextField getPathDisplay() {
            if (pathDisplay == null) {
                pathDisplay = new JTextField(scriptPath.getPath());

                java.awt.Dimension preferredSize = pathDisplay.getPreferredSize();
                pathDisplay.setMaximumSize(new java.awt.Dimension(Short.MAX_VALUE, preferredSize.height));
                pathDisplay.getDocument().addDocumentListener(this);
                String pathType = actionMode == Options.ActionMode.Copy ? "Copy" : "Restore";
                pathDisplay.setToolTipText(pathType + " path. Script names that are entered without a path will be " +
                        "searched for in this list of semicolon(;) separated paths.");
            }
            
            if(restoreScriptPathWrapper != null) {
                restoreScriptPathWrapper.setJTextField(pathDisplay);
            }
            return pathDisplay;
        }

        public void addDocumentListener() {
            pathDisplay.getDocument().addDocumentListener(this);
        }

        public void removeDocumentListener() {
            pathDisplay.getDocument().removeDocumentListener(this);
        }

        public void changedUpdate(DocumentEvent de) {
            updatePath();
        }

        public void insertUpdate(DocumentEvent de) {
            updatePath();
        }

        public void removeUpdate(DocumentEvent de) {
            updatePath();
        }

        private void updatePath() {
            scriptPath.setPath(pathDisplay.getText());
        }

        public void setDefaults() {
            if (!pathDisplay.getText().equals(scriptPath.getDefaultPath())) {
                pathDisplay.setText(scriptPath.getDefaultPath());
            }
        }
    }
}
